package com.griddroid.serverdaemons;

import java.util.HashMap;
import java.util.Vector;

import com.griddroid.configuration.GridServerConfig;
import com.griddroid.exceptions.FoundAlienWorkRequestException;
import com.griddroid.exceptions.NonCoherentComputationException;
import com.griddroid.exceptions.NotCalculatedComputationException;
import com.griddroid.exceptions.UnknownComputationException;
import com.griddroid.nodes.GridServer;
import com.griddroid.works.WorkResponse;

/**
 * This class represents a MergerDaemon of a server. It extends the abstract class
 * {@link GenericDaemon GenericDaemon} to gain the main functionality of.
 * 
 * @author Charalampos Mavroforakis
 * @author Thomas Ailianos
 * @author Michail Michailidis
 */
public class MergerDaemon extends GenericDaemon
{
	private HashMap<String, Vector<WorkResponse>> mainResponses;

	/**
	 * Constructs a MergerDaemon and installs it into the given {@link GridServer GridServer}
	 * @param server
	 */
	public MergerDaemon(GridServer server)
	{
		this.mainResponses = new HashMap<String, Vector<WorkResponse>>();
		this.server = server;
	}
	/**
	 * Starts the MergerDaemon which is looking for new Work fragment responses and when all 
	 * fragments are collected it merges them producing a {@link WorkRespose WorkResponse}
	 */
	@Override
	public void run()
	{
		while (true)
		{
			while (!this.server.getWorkFragmentResponses().isEmpty())
			{
				WorkResponse wrp = this.server.getWorkFragmentResponses().remove(this.server.getWorkFragmentResponses().size() - 1);
				Vector<WorkResponse> workFragmentVector = mainResponses.get(wrp.getWorkRequestId());
				if (workFragmentVector == null)
				{
					workFragmentVector = new Vector<WorkResponse>();
					this.mainResponses.put(wrp.getWorkRequestId(), workFragmentVector);
				}
				workFragmentVector.add(wrp);
				// System.out.println(wrp.getTotalFragments() + "/" +
				// workFragmentVector.size());
				if (workFragmentVector.size() == wrp.getTotalFragments())
				{
					WorkResponse[] a = new WorkResponse[workFragmentVector.size()];
					try
					{
						WorkResponse mainwrp = wrp.merge(workFragmentVector.toArray(a));
						this.server.getWorkResponses().add(mainwrp);
						this.server.log("Info", "Merger just merged a work response");
						workFragmentVector.removeAllElements();
						this.mainResponses.remove(mainwrp.getWorkRequestId());

					}
					catch (NotCalculatedComputationException e)
					{
						this.server.log("Error", "Could not merge work response!");
					}
					catch (NonCoherentComputationException e)
					{
						this.server.log("Error", "Could not merge work response!");
					}
					catch (UnknownComputationException e)
					{
						this.server.log("Error", "Could not merge work response!");
					}
					catch (FoundAlienWorkRequestException e)
					{
						this.server.log("Error", "Could not merge work response!");
					}

				}
			}

			try
			{
				Thread.sleep(GridServerConfig.CHECKINTERVAL);
			}
			catch (InterruptedException e)
			{
			}
		}
	}

	/**
	 * Exits the MergerDaemon
	 */
	@Override
	public void close()
	{

	}

}
